#include "runtime/dict_object.hpp"
#include "env.hpp"

#include <stdio.h>
#include <map>

int PairObject::compare(Object* o) {
    return _key->compare(o);
}

void PairObject::print() {
    _key->print();
    printf(": ");
    _value->print();
    printf(", ");
}

void PairObject::copy_into_map(std::map<std::string, Object*>* map) {
    if (_left != NULL) {
        _left->copy_into_map(map);
    }

    (*map)[std::string(((StringObject*)_key)->value())] = _value;

    if (_right != NULL) {
        _right->copy_into_map(map);
    }
}

DictObject* DictObject::from_stack_frame(StackFrame* frame) {
    std::map<std::string, Object*>* src = frame->get_map();
    DictObject* dict = new DictObject();

    for (auto iter = src->begin(); iter != src->end(); iter++) {
        dict->put(new StringObject(iter->first.c_str()), iter->second);
    }
    
    return dict;
}

void DictObject::copy_into_map(std::map<std::string, Object*>* map) {
    if (_root == NULL) {
        return;
    }
    
    _root->copy_into_map(map);
}

void DictObject::put(Object* key, Object* value) {
    if (_root == NULL) {
        _root = new PairObject(key, value, NULL);
        return;
    }

    PairObject* target = _root;
    PairObject* parent = NULL;
    int cmp = 0;
    while (target != NULL) {
        cmp = target->compare(key);
        if (cmp == 0) {
            target->set_value(value);
            return;
        }
        else if (cmp < 0) {
            parent = target;
            target = target->right();
        }
        else {
            parent = target;
            target = target->left();
        }
    }
    
    if (cmp < 0) {
        parent->set_right(new PairObject(key, value, parent));
    }
    else {
        parent->set_left(new PairObject(key, value, parent));
    }
}

Object* DictObject::find(Object* key) {
    if (_root == NULL) {
        return NULL;
    }

    PairObject* target = _root;
    int cmp = 0;
    while (target != NULL) {
        cmp = target->compare(key);
        if (cmp == 0) {
            return target->value();
        }
        else if (cmp < 0) {
            target = target->right();
        }
        else {
            target = target->left();
        }
    }
    
    return NULL;
}

void DictObject::print() {
    printf("{");
    printf("}");
}
